home *** CD-ROM | disk | FTP | other *** search
/ Gekkan Dennou Club 147 / Gekkan Dennou Club - 2000.8 Vol. 147 (Japan).7z / Gekkan Dennou Club - 2000.8 Vol. 147 (Japan) (Track 1).bin / docs / complex / mandel.c < prev    next >
C/C++ Source or Header  |  2000-06-05  |  4KB  |  196 lines

  1. #include <stdio.h>
  2. #include <setjmp.h>
  3. #include <iocslib.h>
  4. #include <math.h>
  5. #include <time.h>
  6. #include "complex.h"
  7.  
  8. #define USAGE "\
  9. マンデルブロ集合を描く\n\
  10. 使用法: mandel [reMin imMax scLen [scSize [mxCnt]]]\n\
  11.   漸化式の初期値について reMin=実部最小, imMax=虚部最大, scLen=辺の長さ\n\
  12.   scSize=画面サイズ(0…256×256ドット, 1…512×512ドット)[0]\n\
  13.   mxCnt=回数制限(1~65535)[256]\n\
  14. "
  15.  
  16. /* 画面サイズのデフォルト */
  17. #define SC_SIZE 0
  18.  
  19. /* 計算範囲のデフォルト */
  20. #define RE_MIN (-2.0)
  21. #define IM_MAX (2.0)
  22. #define SC_LEN (4.0)
  23.  
  24. /* 最大ループ回数のデフォルト */
  25. #define MX_CNT 256
  26.  
  27. /* キーチェック */
  28. #define keysns() \
  29. ({ \
  30.   int _k_ = 0; \
  31.   while (B_KEYSNS()) _k_ = B_KEYINP() & 0xff ? : _k_; \
  32.   _k_; \
  33. })
  34.  
  35. double reMin = RE_MIN;  /* 実部最小 */
  36. double imMax= IM_MAX;  /* 虚部最大 */
  37. double scLen = SC_LEN;  /* 辺の長さ */
  38. int scSize = SC_SIZE;  /* 画面サイズ(0…256×256ドット, 1…512×512ドット) */
  39. int mxCnt = MX_CNT;  /* 回数制限(1~65535) */
  40.  
  41. unsigned short *paTable;  /* パレットテーブル */
  42.  
  43. void make_palet_table(void);  /* パレットテーブルを作る */
  44. void init_screen(void);  /* 画面の初期化 */
  45. void tini_screen(void);  /* 画面の後始末 */
  46.  
  47. /* 初期値cでマンデルブロ集合の漸化式の反復回数を返す */
  48. int iteration(complex c, int limit_cnt)
  49. {
  50.   complex z;
  51.   int cnt;
  52.  
  53.   if (setjmp(cjmpenv)) {
  54.     return limit_cnt;  /* 計算できなかった */
  55.   }
  56.   cnt = limit_cnt;
  57.   z = c;
  58.   while (cnt > 0 && cabs2(z) <= 4.0) {
  59.     /* マンデルブロ集合の漸化式 z=z^2+c */
  60.     z = cadd(cpow2(z), c);
  61.     cnt--;
  62.   }
  63.   return limit_cnt - cnt;
  64. }
  65.  
  66. /* 描画ルーチンの本体 */
  67. void draw_body()
  68. {
  69.   unsigned short *a;
  70.   complex c;
  71.   double step;
  72.   unsigned short scCnt;
  73.   unsigned short reCnt;
  74.   unsigned short imCnt;
  75.   complex c0;
  76.  
  77.   scCnt = (scSize ? 512 : 256);
  78.   step = scLen / (double)scCnt;
  79.  
  80.   /* VRAMの書き込みアドレス */
  81.   a = (unsigned short *)0xc00000;
  82.  
  83.   c0 = tocomplex(reMin, imMax);
  84.  
  85.   /* 虚軸方向のループ */
  86.   for (imCnt = 0; imCnt < scCnt; imCnt++) {
  87.     {
  88.       unsigned short *b;
  89.       b = a;
  90.       /* これから描画するラスタを示すための点線を描く */
  91.       for (reCnt = 0; reCnt < 512; reCnt += 8) {
  92.     *b = 0xffff;
  93.     b += 8;
  94.       }
  95.     }
  96.  
  97.     c = c0;
  98.  
  99.     /* 解像度に応じて実軸方向のループ全体を分ける */
  100.     if (scSize == 0) {
  101.       /* 256×256ドット */
  102.  
  103.       /* 実軸方向のループ */
  104.       for (reCnt = 0; reCnt < scCnt; reCnt++) {
  105.     unsigned short col;
  106.  
  107.     /* 漸化式の反復回数を数えてパレットテーブルを参照する */
  108.     col = paTable[iteration(c, mxCnt)];
  109.  
  110.     /* 解像度に応じた大きさの点をVRAMに書き込む */
  111.     *a++ = col;
  112.     *a++ = col;
  113.     a[512-2] = col;
  114.     a[512-1] = col;
  115.  
  116.     /* 実軸方向に進む */
  117.     Re(c) += step;
  118.       }
  119.     } else {
  120.       /* 512×512ドット */
  121.  
  122.       /* 実軸方向のループ */
  123.       for (reCnt = 0; reCnt < scCnt; reCnt++) {
  124.     /* 漸化式の反復回数を数えてパレットテーブルを参照する */
  125.     /* 解像度に応じた大きさの点をVRAMに書き込む */
  126.     *a++ = paTable[iteration(c, mxCnt)];
  127.  
  128.     /* 実軸方向に進む */
  129.     Re(c) += step;
  130.       }
  131.     }
  132.  
  133.     /* 解像度に応じてVRAMの書き込みアドレスを補正する */
  134.     if (scSize == 0) {
  135.       a += 512;
  136.     }
  137.  
  138.     /* 虚軸方向に進む */
  139.     Im(c0) -= step;
  140.  
  141.     /* キーが押されたら中止 */
  142.     if (keysns()) {
  143.       break;
  144.     }
  145.   }
  146. }
  147.  
  148. void main(int argc, char *argv[])
  149. {
  150.   clock_t tm0, tm1;
  151.  
  152.   /* 画面の初期化 */
  153.   init_screen();
  154.  
  155.   /* コマンドラインのパラメータを取得 */
  156.   switch (argc) {
  157.   case 6:
  158.     sscanf(argv[5], "%d", &mxCnt);
  159.   case 5:
  160.     sscanf(argv[4], "%d", &scSize);
  161.   case 4:
  162.     sscanf(argv[3], "%lf", &scLen);
  163.     sscanf(argv[2], "%lf", &imMax);
  164.     sscanf(argv[1], "%lf", &reMin);
  165.   case 1:
  166.     break;
  167.   default:
  168.     printf(USAGE);
  169.     return;
  170.   }
  171.  
  172.   /* パレットテーブルを作る */
  173.   make_palet_table();
  174.  
  175.   /* スーパーバイザモードへ移行 */
  176.   B_SUPER(0);
  177.  
  178.   /* 計測開始 */
  179.   {
  180.     clock_t t = clock();
  181.     while ((tm0 = clock()) == t);
  182.   }
  183.  
  184.   /* 描画ルーチンの本体 */
  185.   draw_body();
  186.  
  187.   /* 計測終了 */
  188.   tm1 = clock();
  189.  
  190.   /* 画面の後始末 */
  191.   tini_screen();
  192.  
  193.   /* 所要時間を表示 */
  194.   printf("所要時間は %.8g 秒です.\n", ((double)(tm1 - tm0)) / CLK_TCK);
  195. }
  196.